home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
The World of Computer Software.iso
/
faq-s.zip
/
STACK5.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1991-03-13
|
5KB
|
131 lines
{***********************************************************
Stack5 - A unit to report stack usage information
by Richard S. Sadowsky
version 2.0 10/16/88
for Turbo Pascal version 5.0
released to the public domain
Inspired by an idea by Kim Kokkonen and Brian Foley.
This unit, when used in a Turbo Pascal 5.0 program, will
automatically report information about stack usage. This
is very useful during program development. The following
information is reported about the stack automatically when
the program terminates (just add this unit to your USES
clause):
Total stack space
Unused stack space
Stack spaced used by your program
This unit is extremely similar to the file STKUSE.ARC
in BPROGA LIB 6 on Compuserve. The difference is that
this file has been adapted for use with Turbo Pascal 5,
whereas STKUSE works with TP4. Since this program
uses a hacker's technique to get the total stack value,
it is somewhat version specific.
The unit's initialization code handles three things, it
figures out the total stack space, it initializes the
unused stack space to a known value, and it sets up an
ExitProc to automatically report the stack usage at
termination. The total stack space is calculated by
adding 8 to the current stack pointer on entry into
the unit.
The ExitProc StackReport handles the math of calculating
the used and unused amount of stack space, and displays
this information. Note that the original ExitProc
(Sav_ExitProc) is restored immediately on entry to
StackReport. This is a good idea in ExitProc in case
a runtime (or I/O) error occurs in your ExitProc!
Despite the fact that Brian Foley has pointed out some
flaws in the method's used by this program, and uploaded
his own TPSTACK unit which handles things somewhat
differently (and also reports heap usage), I've decided to
post this update. The reason is that Brian's TPStack
reprograms the timer, and therefore can't be used (as
currently implemented) with other units or programs
that reprogram the timer. While in development, I often
use TPTimer for high resolution timing, but also need to
know the stack usage. The main flaw in my technique
that Brian has pointed out is that it will not catch
stack space reserved by a routine but not used.
Consider the following:
procedure EatTheStack;
var
BigLocalVar : Array[1..MAXINT] of Char;
begin
end;
Stack5 will not show that this massive variable used
any stack space (which of course it does, MAXINT chars
worth) because the values in BigLocalVar have not been
modified. Since I generally use any variables I declare
(otherwise why waste the space), this doesn't present
a major problem for me in most applications. In apps
where it matters, I use Brian's TPStack, which reprograms
the timer to tick more frequently, and "samples" the stack
and heap sizes. Since SP is actually examined, his
technique will show the above BigLocalVar's stack usage.
I hope you find this unit as useful as I have!
***********************************************************}
{$R-,S-} { we don't need no stinkin range or stack checking! }
unit Stack5;
interface
const
StackInitValue = $AA; { the value to initialize the stack to. }
SAFETY = 20; { This value is used as a safety buffer }
{ when initializing the stack to the }
{ StackInitValue. This default of 20 }
{ is safe and shouldn't be lowered. }
var
Sav_ExitProc : Pointer; { to save the previous ExitProc }
StartSPtr : Word; { holds the total stack size }
implementation
{$F+} { this is an ExitProc so it must be compiled as far }
procedure StackReport;
{ This procedure may take a second or two to execute, especially }
{ if you have a large stack. The time is spent examining the }
{ stack looking for our init value (StackInitValue). }
var
I : Word;
begin
ExitProc := Sav_ExitProc; { restore original exitProc first }
I := 0;
{ step through stack from bottom looking for StackInitValue,}
{ stop when found }
while I < SPtr do
if Mem[SSeg:I] <> StackInitValue then begin
{ found StackInitValue so report the stack usage info }
WriteLn;
WriteLn('Total stack space : ',StartSPtr);
WriteLn('Unused stack space: ', I);
WriteLn('Stack space used : ',StartSPtr - I);
I := SPtr; { end the loop }
end
else
inc(I); { look in next byte }
end;
{$F-}
begin
StartSPtr := SPtr + 8; { grab the current SP and account for used space }
FillChar(Mem[SSeg:0], SPtr - SAFETY, StackInitValue); { init the stack }
Sav_ExitProc := ExitProc; { save exitproc }
ExitProc := @StackReport; { set our exitproc }
end.